home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1995 October / EnigmA AMIGA RUN 01 (1995)(G.R. Edizioni)(IT)[!][issue 1995-10][Aminet 7].iso / Aminet / gfx / show / svoUtah22.lha / svoUtahRLE / source / URT / lib / dither.c < prev    next >
C/C++ Source or Header  |  1991-08-09  |  8KB  |  282 lines

  1. /*
  2.  * This software is copyrighted as noted below.  It may be freely copied,
  3.  * modified, and redistributed, provided that the copyright notice is 
  4.  * preserved on all copies.
  5.  * 
  6.  * There is no warranty or other guarantee of fitness for this software,
  7.  * it is provided solely "as is".  Bug reports or fixes may be sent
  8.  * to the author, who may or may not act on them as he desires.
  9.  *
  10.  * You may not include this software in a program or other software product
  11.  * without supplying the source, or without informing the end-user that the 
  12.  * source is available for no extra charge.
  13.  *
  14.  * If you modify this software, you should include a notice giving the
  15.  * name of the person performing the modification, the date of modification,
  16.  * and the reason for such modification.
  17.  *
  18.  *  Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
  19.  *  to have all "void" functions so declared.
  20.  */
  21. /* 
  22.  * dither.c - Functions for RGB color dithering.
  23.  * 
  24.  * Author:    Spencer W. Thomas
  25.  *         Computer Science Dept.
  26.  *         University of Utah
  27.  * Date:    Mon Feb  2 1987
  28.  * Copyright (c) 1987, University of Utah
  29.  */
  30.  
  31. #include <math.h>
  32.  
  33. #ifdef USE_PROTOTYPES
  34. void    make_square( double, int [256], int [256], int [16][16] );
  35. #else
  36. void    make_square();
  37. #endif
  38.  
  39. static int magic4x4[4][4] =  {
  40.       0, 14,  3, 13,
  41.     11,  5,  8,  6,
  42.     12,  2, 15,  1,
  43.      7,  9,  4, 10
  44. };
  45.  
  46. /* basic dithering macro */
  47. #define DMAP(v,x,y)    (modN[v]>magic[x][y] ? divN[v] + 1 : divN[v])
  48.  
  49.  
  50. /*****************************************************************
  51.  * TAG( dithermap )
  52.  * 
  53.  * Create a color dithering map with a specified number of intensity levels.
  54.  * Inputs:
  55.  *     levels:        Intensity levels per primary.
  56.  *    gamma:        Display gamma value.
  57.  * Outputs:
  58.  *     rgbmap:        Generated color map.
  59.  *    divN:        "div" function for dithering.
  60.  *    modN:        "mod" function for dithering.
  61.  * Assumptions:
  62.  *     rgbmap will hold levels^3 entries.
  63.  * Algorithm:
  64.  *    Compute gamma compensation map.
  65.  *    N = 255.0 / (levels - 1) is number of pixel values per level.
  66.  *    Compute rgbmap with red ramping fastest, green slower, and blue
  67.  *    slowest (treat it as if it were rgbmap[levels][levels][levels][3]).
  68.  *    Call make_square to get divN, modN, and magic
  69.  *
  70.  * Note:
  71.  *    Call dithergb( x, y, r, g, b, levels, divN, modN, magic ) to get index
  72.  *    into rgbmap for a given color/location pair, or use
  73.  *        row = y % 16; col = x % 16;
  74.  *        DMAP(v,col,row) =def (divN[v] + (modN[v]>magic[col][row] ? 1 : 0))
  75.  *        DMAP(r,col,row) + DMAP(g,col,row)*levels + DMAP(b,col,row)*levels^2
  76.  *    if you don't want function call overhead.
  77.  */
  78. void
  79. dithermap( levels, gamma, rgbmap, divN, modN, magic )
  80. double gamma;
  81. int rgbmap[][3];
  82. int divN[256];
  83. int modN[256];
  84. int magic[16][16];
  85. {
  86.     double N;
  87.     register int i;
  88.     int levelsq, levelsc;
  89.     int gammamap[256];
  90.     
  91.     for ( i = 0; i < 256; i++ )
  92.     gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
  93.  
  94.     levelsq = levels*levels;    /* squared */
  95.     levelsc = levels*levelsq;    /* and cubed */
  96.  
  97.     N = 255.0 / (levels - 1);    /* Get size of each step */
  98.  
  99.     /* 
  100.      * Set up the color map entries.
  101.      */
  102.     for(i = 0; i < levelsc; i++) {
  103.     rgbmap[i][0] = gammamap[(int)(0.5 + (i%levels) * N)];
  104.     rgbmap[i][1] = gammamap[(int)(0.5 + ((i/levels)%levels) * N)];
  105.     rgbmap[i][2] = gammamap[(int)(0.5 + ((i/levelsq)%levels) * N)];
  106.     }
  107.  
  108.     make_square( N, divN, modN, magic );
  109. }
  110.  
  111.  
  112. /*****************************************************************
  113.  * TAG( bwdithermap )
  114.  * 
  115.  * Create a color dithering map with a specified number of intensity levels.
  116.  * Inputs:
  117.  *     levels:        Intensity levels.
  118.  *    gamma:        Display gamma value.
  119.  * Outputs:
  120.  *     bwmap:        Generated black & white map.
  121.  *    divN:        "div" function for dithering.
  122.  *    modN:        "mod" function for dithering.
  123.  * Assumptions:
  124.  *     bwmap will hold levels entries.
  125.  * Algorithm:
  126.  *    Compute gamma compensation map.
  127.  *    N = 255.0 / (levels - 1) is number of pixel values per level.
  128.  *    Compute bwmap for levels entries.
  129.  *    Call make_square to get divN, modN, and magic.
  130.  * Note:
  131.  *    Call ditherbw( x, y, val, divN, modN, magic ) to get index into 
  132.  *    bwmap for a given color/location pair, or use
  133.  *        row = y % 16; col = x % 16;
  134.  *        divN[val] + (modN[val]>magic[col][row] ? 1 : 0)
  135.  *    if you don't want function call overhead.
  136.  *    On a 1-bit display, use
  137.  *        divN[val] > magic[col][row] ? 1 : 0
  138.  */
  139. void
  140. bwdithermap( levels, gamma, bwmap, divN, modN, magic )
  141. double gamma;
  142. int bwmap[];
  143. int divN[256];
  144. int modN[256];
  145. int magic[16][16];
  146. {
  147.     double N;
  148.     register int i;
  149.     int gammamap[256];
  150.     
  151.     for ( i = 0; i < 256; i++ )
  152.     gammamap[i] = (int)(0.5 + 255 * pow( i / 255.0, 1.0/gamma ));
  153.  
  154.     N = 255.0 / (levels - 1);    /* Get size of each step */
  155.  
  156.     /* 
  157.      * Set up the color map entries.
  158.      */
  159.     for(i = 0; i < levels; i++)
  160.     bwmap[i] = gammamap[(int)(0.5 + i * N)];
  161.  
  162.     make_square( N, divN, modN, magic );
  163. }
  164.  
  165.  
  166. /*****************************************************************
  167.  * TAG( make_square )
  168.  * 
  169.  * Build the magic square for a given number of levels.
  170.  * Inputs:
  171.  *     N:        Pixel values per level (255.0 / levels).
  172.  * Outputs:
  173.  *     divN:        Integer value of pixval / N
  174.  *    modN:        Integer remainder between pixval and divN[pixval]*N
  175.  *    magic:        Magic square for dithering to N sublevels.
  176.  * Assumptions:
  177.  *     
  178.  * Algorithm:
  179.  *    divN[pixval] = (int)(pixval / N) maps pixval to its appropriate level.
  180.  *    modN[pixval] = pixval - (int)(N * divN[pixval]) maps pixval to
  181.  *    its sublevel, and is used in the dithering computation.
  182.  *    The magic square is computed as the (modified) outer product of
  183.  *    a 4x4 magic square with itself.
  184.  *    magic[4*k + i][4*l + j] = (magic4x4[i][j] + magic4x4[k][l]/16.0)
  185.  *    multiplied by an appropriate factor to get the correct dithering
  186.  *    range.
  187.  */
  188. void
  189. make_square( N, divN, modN, magic )
  190. double N;
  191. int divN[256];
  192. int modN[256];
  193. int magic[16][16] ;
  194. {
  195.     register int i, j, k, l;
  196.     double magicfact;
  197.  
  198.     for ( i = 0; i < 256; i++ )
  199.     {
  200.     divN[i] = (int)(i / N);
  201.     modN[i] = i - (int)(N * divN[i]);
  202.     }
  203.     modN[255] = 0;        /* always */
  204.  
  205.     /*
  206.      * Expand 4x4 dither pattern to 16x16.  4x4 leaves obvious patterning,
  207.      * and doesn't give us full intensity range (only 17 sublevels).
  208.      * 
  209.      * magicfact is (N - 1)/16 so that we get numbers in the matrix from 0 to
  210.      * N - 1: mod N gives numbers in 0 to N - 1, don't ever want all
  211.      * pixels incremented to the next level (this is reserved for the
  212.      * pixel value with mod N == 0 at the next level).
  213.      */
  214.     magicfact = (N - 1) / 16.;
  215.     for ( i = 0; i < 4; i++ )
  216.     for ( j = 0; j < 4; j++ )
  217.         for ( k = 0; k < 4; k++ )
  218.         for ( l = 0; l < 4; l++ )
  219.             magic[4*k+i][4*l+j] =
  220.             (int)(0.5 + magic4x4[i][j] * magicfact +
  221.                   (magic4x4[k][l] / 16.) * magicfact);
  222. }
  223.  
  224.  
  225. /*****************************************************************
  226.  * TAG( dithergb )
  227.  * 
  228.  * Return dithered RGB value.
  229.  * Inputs:
  230.  *     x:        X location on screen of this pixel.
  231.  *    y:        Y location on screen of this pixel.
  232.  *    r, g, b:    Color at this pixel (0 - 255 range).
  233.  *    levels:        Number of levels in this map.
  234.  *    divN, modN:    From dithermap.
  235.  *    magic:        Magic square from dithermap.
  236.  * Outputs:
  237.  *     Returns color map index for dithered pixelv value.
  238.  * Assumptions:
  239.  *     divN, modN, magic were set up properly.
  240.  * Algorithm:
  241.  *     see "Note:" in dithermap comment.
  242.  */
  243. dithergb( x, y, r, g, b, levels, divN, modN, magic )
  244. int divN[256];
  245. int modN[256];
  246. int magic[16][16];
  247. {
  248.     int col = x % 16, row = y % 16;
  249.  
  250.     return DMAP(r, col, row) +
  251.     DMAP(g, col, row) * levels +
  252.         DMAP(b, col, row) * levels*levels;
  253. }
  254.  
  255.  
  256. /*****************************************************************
  257.  * TAG( ditherbw )
  258.  * 
  259.  * Return dithered black & white value.
  260.  * Inputs:
  261.  *     x:        X location on screen of this pixel.
  262.  *    y:        Y location on screen of this pixel.
  263.  *    val:        Intensity at this pixel (0 - 255 range).
  264.  *    divN, modN:    From dithermap.
  265.  *    magic:        Magic square from dithermap.
  266.  * Outputs:
  267.  *     Returns color map index for dithered pixel value.
  268.  * Assumptions:
  269.  *     divN, modN, magic were set up properly.
  270.  * Algorithm:
  271.  *     see "Note:" in bwdithermap comment.
  272.  */
  273. ditherbw( x, y, val, divN, modN, magic )
  274. int divN[256];
  275. int modN[256];
  276. int magic[16][16];
  277. {
  278.     int col = x % 16, row = y % 16;
  279.  
  280.     return DMAP(val, col, row);
  281. }
  282.